home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 21 / Mac Magazin and MacEasy Magazine CD - Issue 21.iso / Wissenschaft & Technik / yorick12vr1-ppc folder / startup / zbuf.i < prev   
Text File  |  1996-02-08  |  26KB  |  890 lines

  1. /*
  2.    ZBUF.I
  3.    Yorick interface to z-buffered graphics. Uses same interface
  4.    as Munro's plwf, but scales coords to fit into the z-buffer
  5.    range.
  6.  
  7.    $Id: zbuf.i,v 1.1 1994/11/10 23:13:12 langer Exp $
  8.  */
  9. /*    Copyright (c) 1994.  The Regents of the University of California.
  10.                     All rights reserved.  */
  11.  
  12. /*
  13. require, "plwf.i";
  14. */
  15.  
  16. extern zbuf_terp, pixbuf_terp;
  17. extern nx_zbuf_terp, ny_zbuf_terp;
  18. extern x_viewpoint, y_viewpoint, z_viewpoint;
  19. extern trans_vec1, trans_vec2, trans_vec3;
  20. extern fixed_map, no_project, use_viewpoint;
  21. extern view_box, view_world, view_dist;
  22. use_viewpoint= 1;
  23. no_project= 1;
  24. x_viewpoint= y_viewpoint= z_viewpoint= 0.0;
  25. view_box= array(0.0, 2, 2);
  26.  
  27.  
  28. /* ------------------------------------------------------------------------ */
  29.  
  30. func draw_tri(x, y, z, colr)
  31. /* DOCUMENT draw_tri(x, y, z, colr)
  32.      draws the triangle with corners at (x,y,z) where the three
  33.      variables are all vectors of length 3. colr may be either a scalar
  34.      color index for the whole triangle or a length 3 vector for the
  35.      three corners. Draws into the z-buffer which is later strobed
  36.      to the screen. The points are transformed using the current
  37.      projection.
  38.  
  39.    SEE ALSO: show_zbuf, set_proj;
  40.  */
  41. {
  42.   if(numberof(x) != 3 || numberof(y) != 3 || numberof(z) != 3) {
  43.     error,"coordinate array is not length three in draw_tri";
  44.   }
  45.   if(numberof(colr) != 1 && numberof(colr) != 3) {
  46.     error,"color must be of length 1 or 3 in draw_tri";
  47.   }
  48.   /* transform from world coords to viewpoint coords */
  49.   do_trans, x, y, z;
  50.   /* project the x and y coords */
  51.   project, x, y, z;
  52.   pick_viewbox, x, y;
  53.   map_to_scrn, x, y;
  54.   /* don't take a chance on the type of colr */
  55.   colr= char(colr);
  56.   if(numberof(colr) == 1) {
  57.     tri_draw_1c, x, y, z, colr;
  58.   } else {
  59.     tri_draw, x, y, z, colr;
  60.   }
  61.   show_zbuf;
  62. }
  63.  
  64. func draw_quad_strip(x, y, z, colr)
  65. /* DOCUMENT draw_quad_strip(x, y, z, colr)
  66.      draws the strip of quads with corners at (x,y,z). 
  67.      Dimensions for x,y,z are n by 2.
  68.      One quad (two triangles) is drawn for each group of four points, so
  69.      there are n-1 quads (2*(n-1) triangles). colr is a list
  70.      of color indices and may be either length n-1 to specify an
  71.      index for each quad or length n by 2 to specify an
  72.      index for each vertex, in which case the color of each point
  73.      is interpolated from the surrounding 3 vertices.
  74.      Draws into the z-buffer which is later strobed
  75.      to the screen. The points are transformed using the current
  76.      projection.
  77.  
  78.    SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list, draw_tri_strip;
  79.  */
  80. {
  81.   dimsx= dimsof(x);
  82.   dimsy= dimsof(y);
  83.   dimsz= dimsof(z);
  84.   dimsc= dimsof(colr);
  85.   if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
  86.     error,"x,y,z arrays do not have same shape in draw_quad_strip";
  87.   }
  88.   if(dimsx(1) != 2) {
  89.     error,"coordinate arrays must be two dimensional in draw_quad_strip";
  90.   }
  91.   if(dimsx(3) != 2) {
  92.     error,"coordinate arrays must be n by 2 in draw_quad_strip";
  93.   }
  94.   num= dimsx(2);
  95.   if(dimsc(1) == 1) {
  96.     if(dimsc(2) != num-1) {
  97.       error,"color array must be n-1 vector or n by 2 in draw_quad_strip";
  98.     }
  99.     /* one color per triangle */
  100.     one_colr= 1;
  101.   } else if(anyof(dimsx != dimsc)) {
  102.     error,"color array must be n-1 vector or n by 2 in draw_quad_strip";
  103.   } else {
  104.     /* one color index per vertex */
  105.     one_colr= 0;
  106.   }
  107.   /* transform from world coords to viewpoint coords */
  108.   do_trans, x, y, z;
  109.   /* project the x and y coords */
  110.   project, x, y, z;
  111.   pick_viewbox, x, y;
  112.   map_to_scrn, x, y;
  113.   /* don't take a chance on the type of colr */
  114.   colr= char(colr);
  115.   if(one_colr) {
  116.     quad_strip_1c, numberof(x(,1)), x(,1), x(,2), y(,1), y(,2), z(,1), z(,2), colr;
  117.   } else {
  118.     quad_strip, numberof(x(,1)), x(,1), x(,2), y(,1), y(,2), z(,1), z(,2), colr(,1), colr(,2);
  119.   }
  120.   show_zbuf;
  121. }
  122.  
  123. func draw_tri_strip(x, y, z, colr)
  124. /* DOCUMENT draw_tri_strip(x, y, z, colr)
  125.      draws the strip of triangles with corners at (x,y,z). 
  126.      One triangle is drawn for each group of three points, so
  127.      there are n-2 triangles if there are n points. colr is a list
  128.      of color indices and may be either length n-2 to specify an
  129.      index for each triangle or length n to specify an
  130.      index for each vertex, in which case the color of each point
  131.      in a triangle is interpolated from the vertices.
  132.      Draws into the z-buffer which is later strobed
  133.      to the screen. The points are transformed using the current
  134.      projection.
  135.  
  136.    SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list;
  137.  */
  138. {
  139.   dimsx= dimsof(x);
  140.   dimsy= dimsof(y);
  141.   dimsz= dimsof(z);
  142.   dimsc= dimsof(colr);
  143.   if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
  144.     error,"x,y,z arrays do not have same shape in draw_tri_strip";
  145.   }
  146.   if(dimsx(1) != 1) {
  147.     error,"coordinate arrays must be one dimensional in draw_tri_strip";
  148.   }
  149.   if(dimsc(1) != 1) {
  150.     error,"color array must be one dimensional in draw_tri_strip";
  151.   }
  152.   if(dimsc(2) == dimsx(2)) {
  153.     /* one color index per vertex */
  154.     one_colr= 0;
  155.   } else if(dimsc(2) == dimsx(2)-2) {
  156.     /* one color index per triangle */
  157.     one_colr= 1;
  158.   } else {
  159.     error,"number of colors must equal number of vertices or two less for draw_tri_strip";
  160.   }
  161.   /* transform from world coords to viewpoint coords */
  162.   do_trans, x, y, z;
  163.   /* project the x and y coords */
  164.   project, x, y, z;
  165.   pick_viewbox, x, y;
  166.   map_to_scrn, x, y;
  167.   num= dimsx(2);
  168.   /* don't take a chance on the type of colr */
  169.   colr= char(colr);
  170.   if(one_colr) {
  171.     tri_strip_1c, num, x, y, z, colr;
  172.   } else {
  173.     tri_strip, num, x, y, z, colr;
  174.   }
  175.   show_zbuf;
  176. }
  177.  
  178. func draw_tri_list(x, y, z, colr)
  179. /* DOCUMENT draw_tri_list(x, y, z, colr)
  180.      x,y,z have dimensions 3 by n. This function draws the 
  181.      triangles with corners at (x(,j),y(,j),z(,j)). 
  182.      colr is a list of color indices and may be either n to specify an
  183.      index for each triangle or size 3 by n to specify an
  184.      index for each vertex, in which case the color of each point
  185.      in a triangle is interpolated from the vertices.
  186.      Draws into the z-buffer which is later strobed
  187.      to the screen. The points are transformed using the current
  188.      projection.
  189.  
  190.    SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_strip;
  191.  */
  192. {
  193.   dimsx= dimsof(x);
  194.   dimsy= dimsof(y);
  195.   dimsz= dimsof(z);
  196.   dimsc= dimsof(colr);
  197.   if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
  198.     error,"x,y,z arrays do not have same shape in draw_tri_list";
  199.   }
  200.   if(dimsx(1) != 2) {
  201.     error,"coordinate arrays must be two dimensional in draw_tri_list";
  202.   }
  203.   if(dimsx(2) != 3) {
  204.     error,"coordinate arrays must have length 3 for first index in draw_tri_list";
  205.   }
  206.   if(dimsc(1) == 1) {
  207.     /* should be one index per triangle */
  208.     if(dimsc(2) != dimsx(3)) {
  209.       error,"color array must be one per triangle or one per vertex in draw_tri_list";
  210.     }
  211.     one_colr= 1;
  212.   } else if(dimsc(2) != 2) {
  213.     error,"color array must be one or two dimensional in draw_tri_list";
  214.   } else if(dimsc(3) != dimsx(3)) {
  215.     error,"color array must be one per triangle or one per vertex in draw_tri_list";
  216.   } else {
  217.     one_colr= 0;
  218.   }
  219.   /* transform from world coords to viewpoint coords */
  220.   do_trans, x, y, z;
  221.   /* project the x and y coords */
  222.   project, x, y, z;
  223.   pick_viewbox, x, y;
  224.   map_to_scrn, x, y;
  225.   num= dimsx(3);
  226.   /* don't take a chance on the type of colr */
  227.   colr= char(colr);
  228.   if(one_colr) {
  229.     for(i= 1; i <= num; i++) {
  230.       tri_draw_1c, x(,i), y(,i), z(,i), colr(i);
  231.     }
  232.   } else {
  233.     for(i= 1; i <= num; i++) {
  234.       tri_draw, x(,i), y(,i), z(,i), colr(,i);
  235.     }
  236.   }
  237.   show_zbuf;
  238. }
  239.  
  240. func draw_poly_list( npolys, x, y, z, colr)
  241. /* DOCUMENT draw_poly_list( npolys, x, y, z, colr)
  242.      x, y, z are lists of vertex coordinates. npolys is an array
  243.      with the number of vertices per polygon. colr is the color index 
  244.      for each polygon and has the same length as npolys.
  245.      x,y,z have length equal to sum(npolys). This function draws the 
  246.      polygons with corners at (x(ilo),y(ilo),z(ilo)) through ihi,
  247.      where ilo and ihi are determined from a psum of npolys. 
  248.      Draws into the z-buffer which is later strobed
  249.      to the screen. The points are transformed using the current
  250.      projection.
  251.  
  252.    SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list;
  253.  */
  254. {
  255.   num= numberof(npolys);
  256.   pspans= npolys(psum);
  257.   dimsx= dimsof(x);
  258.   dimsy= dimsof(y);
  259.   dimsz= dimsof(z);
  260.   dimsc= dimsof(colr);
  261.   if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
  262.     error,"x,y,z arrays do not have same shape in draw_poly_list";
  263.   }
  264.   if(dimsx(1) != 1) {
  265.     error,"coordinate arrays must be one dimensional in draw_poly_list";
  266.   }
  267.   if(dimsc(1) == 1) {
  268.     /* should be one index per triangle */
  269.     if(dimsc(2) != num) {
  270.       error,"must have one color per polygon in draw_poly_list";
  271.     }
  272.   } else {
  273.     error,"color array must be one dimensional in draw_poly_list";
  274.   }
  275.   /* transform from world coords to viewpoint coords */
  276.   do_trans, x, y, z;
  277.   /* project the x and y coords */
  278.   project, x, y, z;
  279.   pick_viewbox, x, y;
  280.   map_to_scrn, x, y;
  281.   /* don't take a chance on the type of colr */
  282.   colr= char(colr);
  283.   ilo= 1;
  284.   for(j= 1; j <= num; j++) {
  285.     ihi= pspans(j);
  286.     nvert= npolys(j);
  287. // write,format="j=%d, nvert=%d\n",j,nvert;
  288.     /* handle special cases of a triangle and a quad */
  289.     if(nvert == 3) {
  290.       tri_draw_1c, x(ilo:ihi), y(ilo:ihi), z(ilo:ihi), colr(j);
  291. // write,format="triangle(c=%d): (%f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n", 
  292. //   colr(j),x(ilo),y(ilo),z(ilo),x(ilo+1),y(ilo+1),z(ilo+1),x(ihi),y(ihi),z(ihi);
  293.     } else if(nvert == 4) {
  294.       tri_draw_1c, x(ilo:ihi-1), y(ilo:ihi-1), z(ilo:ihi-1), colr(j);
  295.       xx= [x(ilo), x(ilo+2), x(ihi)];
  296.       yy= [y(ilo), y(ilo+2), y(ihi)];
  297.       zz= [z(ilo), z(ilo+2), z(ihi)];
  298.       tri_draw_1c, xx, yy, zz, colr(j);
  299. // write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n", 
  300. //   colr(j),x(ilo),y(ilo),z(ilo),x(ilo+1),y(ilo+1),z(ilo+1),x(ilo+2),y(ilo+2),z(ilo+2);
  301. // write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n", 
  302. //   colr(j),xx(1),yy(1),zz(1),xx(2),yy(2),zz(2),xx(3),yy(3),zz(3);
  303.     } else {
  304.       /* tesselate the polygon into a series of triangles. 
  305.          Assume, FOR NOW!!!, that the triangle is convex. 
  306.          This means that the average of the vertex coords lies
  307.          inside the polygon and can be used as a common point 
  308.          for all the tesellation triangles. */
  309.       xx= yy= zz= array(0.0, 3);
  310.       xx(3)= x(ilo:ihi)(avg);
  311.       yy(3)= y(ilo:ihi)(avg);
  312.       zz(3)= z(ilo:ihi)(avg);
  313.       for(k= ilo; k <= ihi-1; k++) {
  314.         xx(1:2)= x(k:k+1);
  315.         yy(1:2)= y(k:k+1);
  316.         zz(1:2)= z(k:k+1);
  317.         tri_draw_1c, xx, yy, zz, colr(j);
  318. // write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n", 
  319. //   colr(j),xx(1),yy(1),zz(1),xx(2),yy(2),zz(2),xx(3),yy(3),zz(3);
  320.       }
  321.       xx(1)= x(ilo);
  322.       yy(1)= y(ilo);
  323.       zz(1)= z(ilo);
  324.       xx(2)= x(ihi);
  325.       yy(2)= y(ihi);
  326.       zz(2)= z(ihi);
  327.       tri_draw_1c, xx, yy, zz, colr(j);
  328. // write,format="triangle(c=%d): (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)\n", 
  329. //   colr(j),xx(1),yy(1),zz(1),xx(2),yy(2),zz(2),xx(3),yy(3),zz(3);
  330.     }
  331.     ilo= ihi+1;
  332.   }
  333.   show_zbuf;
  334. }
  335.  
  336.  
  337. struct link3d {
  338.   long is_quad, one_colr;
  339.   char *colr;
  340.   double *data_x, *data_y, *data_z;
  341.   double *rot_x, *rot_y, *rot_z;
  342.   double *adj_z;
  343.   double *proj_x, *proj_y;
  344.   double *map_x, *map_y;
  345.   link3d *next;
  346.   link3d *prev;
  347. }
  348.  
  349. func add_link3d(x, y, z, colr)
  350. /* DOCUMENT add_link3d(x, y, z, colr)
  351.    1) draws the strip of triangles with corners at (x,y,z)
  352.       if x, y, and z are 1D arrays. 
  353.       One triangle is drawn for each group of three points, so
  354.       there are n-2 triangles if there are n points. colr is a list
  355.       of color indices.
  356.       If colr has the same length as x, y, z, there is a color
  357.       for each vertex and the colors are interpolated linearly
  358.       between vertices. If colr has length 2 less than x, y, and z, 
  359.       there is a single color for each triangle.
  360.    2) draws the strip of quads with corners at (x,y,z)  
  361.       if the dimensions for x,y,z are n by 2.
  362.       One quad (two triangles) is drawn for each group of four points,
  363.       so there are n-1 quads (2*(n-1) triangles). colr is a list
  364.       of color indices and may be either length n-1 to specify an
  365.       index for each quad or length n by 2 to specify an
  366.       index for each vertex, in which case the color of each point
  367.       is interpolated from the surrounding 3 vertices.
  368.  
  369.    SEE ALSO: show_zbuf, set_proj, draw_tri, draw_tri_list;
  370.  */
  371. {
  372.   dimsx= dimsof(x);
  373.   dimsy= dimsof(y);
  374.   dimsz= dimsof(z);
  375.   dimsc= dimsof(colr);
  376.   if(anyof(dimsx != dimsy) || anyof(dimsx != dimsz)) {
  377.     error,"x,y,z arrays do not have same shape in add_link3d";
  378.   }
  379.   if(dimsx(1) < 1 || dimsx(1) > 2) {
  380.     error,"coordinate arrays must be one or two two dimensional in add_link3d";
  381.   }
  382.   if(dimsx(1) == 1) {
  383.     /* triangle strip */
  384.     is_quad= 0;
  385.     if(dimsc(1) != 1) {
  386.       error,"color array must be one dimensional for triangle strip in add_link3d";
  387.     }
  388.     if(dimsc(2) == dimsx(2)) {
  389.       /* one color index per vertex */
  390.       one_colr= 0;
  391.     } else if(dimsc(2) == dimsx(2)-2) {
  392.       /* one color index per triangle */
  393.       one_colr= 1;
  394.     } else {
  395.       error,"number of colors must equal number of vertices or two less for add_link3d";
  396.     }
  397.   } else {
  398.     /* quad strip */
  399.     is_quad= 1;
  400.     if(dimsx(3) != 2) {
  401.       error,"coordinate arrays must be n by 2 for quad strip in add_link3d";
  402.     }
  403.     num= dimsx(2);
  404.     if(dimsc(1) == 1) {
  405.       if(dimsc(2) != num-1) {
  406.         error,"color array must be n-1 vector or n by 2 for quad strip in add_link3d";
  407.       }
  408.       /* one color per triangle */
  409.       one_colr= 1;
  410.     } else if(anyof(dimsx != dimsc)) {
  411.       error,"color array must be n-1 vector or n by 2 for quad strip in add_link3d";
  412.     } else {
  413.       /* one color index per vertex */
  414.       one_colr= 0;
  415.     }
  416.   }
  417.  
  418.   link= array(link3d);
  419.   link.next= list3d_head.next;
  420.   if(link.next) (link.next)->prev= &link;
  421.   link.prev= &list3d_head;
  422.   list3d_head.next= &link;
  423.  
  424.   link.data_x= &x;
  425.   link.data_y= &y;
  426.   link.data_z= &z;
  427.   link.colr= &colr;
  428.   link.one_colr= one_colr;
  429.   link.is_quad= is_quad;
  430.  
  431.   link.rot_x= link.rot_y= link.rot_z= pointer(0);
  432.   link.proj_x= link.proj_y= pointer(0);
  433.   link.adj_z= pointer(0);
  434.  
  435.   return &link;
  436. }
  437.  
  438. func show_list3d
  439. {
  440.   link= list3d_head.next;
  441.   while(link) {
  442.     if(link->is_quad) {
  443.       xx= *(link->map_x);
  444.       yy= *(link->map_y);
  445.       zz= *(link->adj_z);
  446.       colr= *(link->colr);
  447.       num= numberof( xx(,1) );
  448.       if(link->one_colr) {
  449.         quad_strip_1c, num, xx(,1), xx(,2),  yy(,1), yy(,2), 
  450.                       zz(,1), zz(,2), colr;
  451.       } else {
  452.         quad_strip_1c, num, xx(,1), xx(,2),  yy(,1), yy(,2), 
  453.                       zz(,1), zz(,2), colr(,1), colr(,2);
  454.       }
  455.     } else {
  456.       num= numberof( *(link->map_x) );
  457.       if(link->one_colr) {
  458.         tri_strip_1c, num, *(link->map_x), *(link->map_y), 
  459.                       *(link->adj_z), *(link->colr);
  460.       } else {
  461.         tri_strip, num, *(link->map_x), *(link->map_y), 
  462.                    *(link->adj_z), *(link->colr);
  463.       }
  464.     }
  465.     link= link->next;
  466.   }
  467.   show_zbuf;
  468. }
  469.  
  470. func remov_link3d(link)
  471. {
  472.   if(typeof(link) != "struct_instance") {
  473.     error,"remov_link called with a bad argument, must be a link3d struct";
  474.   }
  475. #if 0
  476.   if(structof(link) != "link3d") {
  477.     error,"remov_link called with a bad argument, must be a link3d struct";
  478.   }
  479. #endif
  480.   if(link.next) (link.next)->prev= link.prev;
  481.   if(link.prev) (link.prev)->next= link.next;
  482. }
  483.  
  484. func clear_list3d(dlist)
  485. {
  486.   while(list3d_head.next) {
  487.     remov_link3d(*(list3d_head.next));
  488.   }
  489. }
  490.  
  491. func rot_list3d
  492. {
  493.   link= list3d_head.next;
  494.   while(link) {
  495.     xx= *(link->data_x);
  496.     yy= *(link->data_y);
  497.     zz= *(link->data_z);
  498.     do_rotn, xx, yy, zz;
  499.     link->rot_x= &xx;
  500.     link->rot_y= &yy;
  501.     link->rot_z= &zz;
  502.     link= link->next;
  503.   }
  504. }
  505.  
  506. func lims_list3d(head)
  507. {
  508.   link= head.next;
  509.   xlo= ylo= zlo= 1.0e200;
  510.   xhi= yhi= zhi= -1.0e200;
  511.   while(link) {
  512.     xlo= min(xlo, min( *(link->rot_x) ) );
  513.     xhi= max(xhi, max( *(link->rot_x) ) );
  514.     ylo= min(ylo, min( *(link->rot_y) ) );
  515.     yhi= max(yhi, max( *(link->rot_y) ) );
  516.     zlo= min(zlo, min( *(link->rot_z) ) );
  517.     zhi= max(zhi, max( *(link->rot_z) ) );
  518.     link= link->next;
  519.   }
  520.   res= array(0.0, 3, 2);
  521.   res(1,1)= xlo;
  522.   res(2,1)= ylo;
  523.   res(3,1)= zlo;
  524.   res(1,2)= xhi;
  525.   res(2,2)= yhi;
  526.   res(3,2)= zhi;
  527.   return res;
  528. }
  529.  
  530. func adj_z_list3d
  531. {
  532.   link= list3d_head.next;
  533.   while(link) {
  534.     zz= *(link->rot_z);
  535.     adj_zvals, zz;
  536.     link->adj_z= &zz;
  537.     link= link->next;
  538.   }
  539. }
  540.  
  541. func proj_list3d
  542. {
  543.   link= list3d_head.next;
  544.   while(link) {
  545.     xx= *(link->rot_x);
  546.     yy= *(link->rot_y);
  547.     project, xx, yy, *(link->adj_z);
  548.     link->proj_x= &xx;
  549.     link->proj_y= &yy;
  550.     link= link->next;
  551.   }
  552. }
  553.  
  554. func set_map_from_list3d
  555. {
  556.   extern zbuf_x_off, zbuf_y_off, zbuf_x_scale, zbuf_y_scale;
  557.  
  558.   /* compute the transformation between projected 3D viewpoint coords
  559.      and z-buffer coords */
  560.   link= list3d_head.next;
  561.   xlo= ylo= 1.0e200;
  562.   xhi= yhi= -1.0e200;
  563.   while(link) {
  564.     xx= *(link->proj_x);
  565.     yy= *(link->proj_y);
  566.     xlo= min(xlo, min(xx));
  567.     xhi= max(xhi, max(xx));
  568.     ylo= min(ylo, min(yy));
  569.     yhi= max(yhi, max(yy));
  570.     link= link->next;
  571.   }
  572.   zbuf_x_off= xlo;
  573.   zbuf_y_off= ylo;
  574.   zbuf_x_scale= nx_zbuf_terp/(xhi-zbuf_x_off);
  575.   zbuf_y_scale= nx_zbuf_terp/(yhi-zbuf_y_off);
  576. }
  577.  
  578. func map_list3d
  579. {
  580.   link= list3d_head.next;
  581.   while(link) {
  582.     xx= *(link->proj_x);
  583.     yy= *(link->proj_y);
  584.     map_to_scrn, xx, yy;
  585.     link->map_x= &xx;
  586.     link->map_y= &yy;
  587.     link= link->next;
  588.   }
  589. }
  590.  
  591. func clr_zbuf
  592. /* DOCUMENT clr_zbuf()
  593.      Clears the z-buffer and sets all pixels to color zero.
  594.    SEE ALSO: init_zbuf
  595.  */
  596. {
  597.   extern zbuf_terp;
  598.   extern pixbuf_terp;
  599.  
  600.   zbuf_terp(..)= -1.0e100;
  601.   pixbuf_terp(..)= char(0);
  602. }
  603.  
  604. func init_zbuf(nx, ny)
  605. /* DOCUMENT init_zbuf()
  606.      Creates the z-buffer (if needed) and the 3D display list.
  607.    SEE ALSO: clr_zbuf
  608.  */
  609. {
  610.   extern zbuf_terp, pixbuf_terp;
  611.   extern nx_zbuf_terp, ny_zbuf_terp;
  612.   extern list3d_head;
  613.  
  614.   if(nx < 4 || ny < 4 || nx > 4096 || ny > 4096) {
  615.     error,"init_zbuf(), nx or ny is out of range";
  616.   }
  617.   if(is_void(list3d_head)) {
  618.     list3d_head= array(link3d);
  619.     list3d_head.data_x= list3d_head.data_y= list3d_head.data_z= pointer(0);
  620.     list3d_head.rot_x= list3d_head.rot_y= list3d_head.rot_z= pointer(0);
  621.     list3d_head.proj_x= list3d_head.proj_y= pointer(0);
  622.     list3d_head.adj_z= pointer(0);
  623.     list3d_head.one_colr= 0;
  624.     list3d_head.is_quad= 0;
  625.   }
  626.   /* make new z-buffer only if sizes have changed */
  627.   if(nx != nx_zbuf_terp || ny != ny_zbuf_terp) {
  628.     nx_zbuf_terp= nx;
  629.     ny_zbuf_terp= ny;
  630.     zbuf_terp= array(0.0, nx, ny);
  631.     pixbuf_terp= array(char(0), nx, ny);
  632.     clr_zbuf;
  633.     _make_zbuf, nx, ny, zbuf_terp, pixbuf_terp;
  634.   }
  635. }
  636.  
  637. func show_zbuf
  638. /* DOCUMENT show_zbuf()
  639.      Display the z-buffered image.
  640.    SEE ALSO: clr_zbuf
  641.  */
  642. {
  643.   extern pixbuf_terp;
  644.  
  645.   /* Use a cell array to show the z-buffered image, and set the
  646.      limits to show the active portion of the viewplane. */
  647.   pli,pixbuf_terp,view_box(1,1),view_box(2,1),view_box(1,2),view_box(2,2);
  648. }
  649.  
  650. func project(&x, &y, z)
  651. /* DOCUMENT project(x, y, z)
  652.      Project the x and y coords onto the projection plane.
  653.      x, y, and z must already be in viewpoint coords.
  654.      Modifies the x and y inputs.
  655.    SEE ALSO: do_rotn, adj_zvals, do_trans
  656.  */
  657. {
  658.   if(no_project) return;
  659.   /* perform perspective projection of the vectors x, y, z */
  660.   if(numberof(x) != numberof(y) || numberof(x) != numberof(z)) {
  661.     error,"vectors of different length passed to project()";
  662.   }
  663.   x= (x-x_viewpoint)*z_viewdist/z;
  664.   y= (y-y_viewpoint)*z_viewdist/z;
  665. }
  666.  
  667. func set_viewdist(vdist)
  668. /* DOCUMENT set_viewdist(view_dist)
  669.      Sets the distance between the viewer and the origin in 
  670.      world coords. as measured along the viewing direction.
  671.    SEE ALSO: set_viewpoint
  672.  */
  673. {
  674.   view_dist= vdist;
  675.   use_viewpoint= 0;
  676. }
  677.  
  678. func set_viewpoint(view_loc)
  679. /* DOCUMENT set_viewpoint(view_loc)
  680.      Sets the point where the viewer is located in world coords. 
  681.    SEE ALSO: set_viewdist
  682.  */
  683. {
  684.   extern view_world;
  685.   
  686.   view_world= view_loc;
  687.   use_viewpoint= 1;
  688. }
  689.  
  690. func adj_zvals(&z)
  691. /* DOCUMENT adj_zvals(z)
  692.      Apply the z-offset part of the viewpoint transform 
  693.      to z. Modifies z. 
  694.    SEE ALSO: do_rotn, do_trans, project
  695.  */
  696. {
  697.   extern z_viewpoint;
  698.  
  699.   /* adjust so viewer is at z=0 */
  700.   z -= z_viewpoint;
  701.   if(max(z) >= 0.0) "Warning: at least one point is behind viewpoint";
  702. }
  703.  
  704. func do_rotn(&x, &y, &z)
  705. /* DOCUMENT do_rotn(x, y, z)
  706.      Apply the rotation part of the viewpoint transform 
  707.      to x, y, and z. Modifies all three args. 
  708.    SEE ALSO: do_trans, adj_zvals, project
  709.  */
  710. {
  711.   extern trans_vec1, trans_vec2, trans_vec3;
  712.  
  713.   if(numberof(x) != numberof(y) || numberof(x) != numberof(z)) {
  714.     error,"vectors of different length passed to do_rotn()";
  715.   }
  716.   xp= trans_vec1(1)*x+trans_vec1(2)*y+trans_vec1(3)*z;
  717.   yp= trans_vec2(1)*x+trans_vec2(2)*y+trans_vec2(3)*z;
  718.   zp= trans_vec3(1)*x+trans_vec3(2)*y+trans_vec3(3)*z;
  719.   x= xp;
  720.   y= yp;
  721.   z= zp;
  722. }
  723.  
  724. func set_rotn(theta, phi, psi)
  725. /* DOCUMENT set_rotn(theta, phi, psi)
  726.      theta and phi specify the viewing direction in
  727.      world coords, and are the direction headed toward the viewer.
  728.      psi is the rotation about the viewing direction and is used
  729.      to get the expected "up" direction.
  730.    SEE ALSO: set_viewpoint, set_trans
  731.  */
  732. {
  733.   extern trans_vec1, trans_vec2, trans_vec3;
  734.  
  735.   /* compute the transformation between world coords and 
  736.      the 3D viewpoint coords */
  737.   snth= sin(theta);
  738.   csth= cos(theta);
  739.   snph= sin(phi);
  740.   csph= cos(phi);
  741.   snpsi= sin(psi);
  742.   cspsi= cos(psi);
  743.   trans_vec1= [-csth*csph*snpsi-snph*cspsi, -csth*snph*snpsi+csph*cspsi,
  744.                snth*snpsi];
  745.   trans_vec2= [-csth*csph*cspsi+snph*snpsi, -csth*snph*cspsi-csph*snpsi,
  746.                snth*cspsi];
  747.   trans_vec3= [snth*csph, snth*snph, csth];
  748. }
  749.  
  750. func do_trans(&x, &y, &z)
  751. /* DOCUMENT do_trans(x, y, z)
  752.      Transform x, y, and z to viewpoint coords.
  753.      Modifies all three args. 
  754.    SEE ALSO: do_rotn, adj_zvals, project
  755.  */
  756. {
  757.   do_rotn,x,y,z;
  758.   adj_zvals,z;
  759. }
  760.  
  761. func set_trans(theta, phi, psi)
  762. /* DOCUMENT set_trans(theta, phi, psi)
  763.      theta and phi specify the viewing direction in
  764.      world coords, and are the direction headed toward the viewer.
  765.      psi is the rotation about the viewing direction and is used
  766.      to get the expected "up" direction.
  767.      The viewpoint must have been set in world coords (or specified
  768.      as a distance from the origin) earlier, but it is
  769.      mapped to viewpoint coords here.
  770.    SEE ALSO: set_viewpoint, set_viewdist, set_rotn
  771.  */
  772. {
  773.   extern x_viewpoint, y_viewpoint, z_viewpoint, view_world, view_dist, use_viewpoint;
  774.   
  775.   set_rotn, theta, phi, psi;
  776.   /* Transform the viewpoint from world coords to viewpoint coords.
  777.      Anything with a z greater than the resulting z_viewpoint cannot be seen */
  778.   if(use_viewpoint) {
  779.     x_viewpoint= trans_vec1(1)*view_world(1)+trans_vec1(2)*view_world(2)+
  780.                trans_vec1(3)*view_world(3);
  781.     y_viewpoint= trans_vec2(1)*view_world(1)+trans_vec2(2)*view_world(2)+
  782.                trans_vec2(3)*view_world(3);
  783.     z_viewpoint= trans_vec3(1)*view_world(1)+trans_vec3(2)*view_world(2)+
  784.                trans_vec3(3)*view_world(3);
  785.   } else {
  786.     x_viewpoint= 0.0;
  787.     y_viewpoint= 0.0;
  788.     z_viewpoint= view_dist;
  789.   }
  790. }
  791.  
  792. func map_to_scrn(&x, &y)
  793. {
  794.   extern zbuf_x_scale, zbuf_y_scale, view_box;
  795.  
  796.   /* NOTE: no clipping here */
  797.   x= (x-view_box(1,1))*zbuf_x_scale+1.0;
  798.   y= (y-view_box(2,1))*zbuf_y_scale+1.0;
  799. }
  800.  
  801. func pick_viewbox_link3d
  802. /* DOCUMENT pick_viewbox_link3d
  803.      Automatically pick the viewing area on the view plane when
  804.      using a 3D display list.
  805.    SEE ALSO: free_viewbox, set_viewbox, map_to_scrn
  806.  */
  807. {
  808.   extern view_box;
  809.  
  810.   lims= lims_list3d(list3d_head);
  811.   /* Set the viewing area to 10% bigger than the range of the objects.
  812.   */
  813.   delx= lims(1,2)-lims(1,1);
  814.   dely= lims(2,2)-lims(2,1);
  815.   view_box= lims(1:2,1:2);
  816.   view_box(1,1) -= 0.05*delx;
  817.   view_box(1,2) += 0.05*delx;
  818.   view_box(2,1) -= 0.05*delx;
  819.   view_box(2,2) += 0.05*delx;
  820.   zbuf_x_scale= (nx_zbuf_terp-1.0)/(view_box(1,2)-view_box(1,1));
  821.   zbuf_y_scale= (ny_zbuf_terp-1.0)/(view_box(2,2)-view_box(2,1));
  822. }
  823.  
  824. func pick_viewbox(xvals, yvals)
  825. /* DOCUMENT pick_viewbox(xvals, yvals)
  826.      Automatically choose a mapping between viewing plane coords
  827.      and coords in the pixel buffer based on the x and y inputs.
  828.    SEE ALSO: free_viewbox, set_viewbox, map_to_scrn
  829.  */
  830. {
  831.   extern zbuf_x_scale, zbuf_y_scale, fixed_map, view_box;
  832.  
  833.   /* do not perform if the user has set a "fixed" mapping */
  834.   if(fixed_map) return;
  835.   /* compute the transformation between projected 3D viewpoint coords
  836.      and z-buffer coords */
  837.   view_box(1,1)= min(xvals);
  838.   view_box(1,2)= max(xvals);
  839.   view_box(2,1)= min(yvals);
  840.   view_box(2,2)= max(yvals);
  841.   zbuf_x_scale= (nx_zbuf_terp-1.0)/(view_box(1,2)-view_box(1,1));
  842.   zbuf_y_scale= (ny_zbuf_terp-1.0)/(view_box(2,2)-view_box(2,1));
  843. }
  844.  
  845. func set_viewbox(xlo, xhi, ylo, yhi)
  846. /* DOCUMENT set_viewbox(xlo, xhi, ylo, yhi)
  847.      Specify the range in x and y, in the viewing plane,
  848.      to map to the pixel buffer.
  849.    SEE ALSO: free_viewbox, pick_viewbox, map_to_scrn
  850.  */
  851. {
  852.   extern zbuf_x_scale, zbuf_y_scale, fixed_map, view_box;
  853.  
  854.   /* hold the mapping between viewing plane coords and screen
  855.      coords fixed as chosen by the user */
  856.   fixed_map= 1;
  857.   /* compute the transformation between projected 3D viewpoint coords
  858.      and z-buffer coords */
  859.   view_box(1,1)= xlo;
  860.   view_box(1,2)= xhi;
  861.   view_box(2,1)= ylo;
  862.   view_box(2,2)= yhi;
  863.   zbuf_x_scale= (nx_zbuf_terp-1.0)/(view_box(1,2)-view_box(1,1));
  864.   zbuf_y_scale= (ny_zbuf_terp-1.0)/(view_box(2,2)-view_box(2,1));
  865. }
  866.  
  867. func free_viewbox
  868. /* DOCUMENT free_viewbox
  869.      The mapping between viewing plane coords and coords in
  870.      the pixel buffer will be set automatically.
  871.    SEE ALSO: pick_viewbox, set_viewbox, map_to_scrn
  872.  */
  873. {
  874.   extern fixed_map;
  875.  
  876.   /* should automatically pick the mapping between viewing plane
  877.      coords and screen coords */
  878.   fixed_map= 0;
  879. }
  880.  
  881. /* create an initial z-buffer and pixmap */
  882. if(numberof(zbuf_terp) < 16) {
  883.   nx_zbuf_terp= 0;
  884.   ny_zbuf_terp= 0;
  885. }
  886. init_zbuf, 64, 64;
  887. free_viewbox;
  888. set_viewpoint, [0.0, 0.0, 100.0];
  889. set_trans, pi/4.0, 0.0, pi/2.0;
  890.